package com.lock.common;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;

/**
 * 基于临时无序节点的分布式锁
 * Created by Administrator on 2017/7/13.
 */
public class FBSLock {
    public static void main(String[] args) {
        Invoke invoke = new Invoke();
        for (int i=0;i<15;i++){
            new Thread(invoke).start();
        }
    }
}
class Invoke implements Runnable{
    private int i;
    private String path = "/lock";
    private static ZooKeeper zooKeeper = null;

    static {
        try {
            zooKeeper = new ZooKeeper("127.0.0.1:2181", 60000, new Watcher() {
                public void process(WatchedEvent watchedEvent) {
                    //System.out.println("触发了事件"+watchedEvent.getType());
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        //获取锁
        //判断是否存在
        if (getLock() == null) {
            //不存在  直接争抢并创建执行
            while (true) {
                if (lock(Thread.currentThread().getName())) {
                    i++;
                    System.out.println(Thread.currentThread().getName() + "直接执行-----------" + i);
                    this.unLock();
                    return;
                } else {
                    System.out.println(Thread.currentThread().getName() + "该线程争抢失败-----------");
                }
            }
        } else {
            //存在
            //获取锁数据是否与当前线程一致
            if (Thread.currentThread().getName().equals(getData())) {
                //一样就执行
                i++;
                System.out.println(Thread.currentThread().getName() + "判断执行-----------" + i);
                this.unLock();
            } else {
                //不一样就返回
                System.out.println("获取锁不一致，返回！！");
            }
        }
    }


    /**
     * 创建锁
     * @param data
     * @return
     */
    public boolean lock(String data){
        try {
            if(getLock() == null) {
                String result = zooKeeper.create(this.path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
                System.out.println("---" + result);
                return true;
            }
        } catch (KeeperException e) {
            return false;
        } catch (InterruptedException e) {
            return false;
        }
        return false;
    }

    /**
     * 删除锁
     * @return
     */
    public boolean unLock(){
        if (getLock() != null) {
            try {
                zooKeeper.delete(this.path,-1);
                return true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (KeeperException e) {
                e.printStackTrace();
            }
            return false;
        }
        return true;
    }

    /**
     * 获取锁
     * @return
     */
    public Stat getLock(){
        try {
            Stat stat = zooKeeper.exists(this.path,false);
            return stat;
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取锁数据
     * @return
     */
    private String getData(){
        try {
            byte[] bytes = zooKeeper.getData(this.path,false,null);
            return bytes.toString();
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
